from eden.evo.aminos import MultiAmino, AddAmino
from eden.evo.cell import SexualCell
from eden.evo.chromosome import Chromosome
from eden.evo.codon import Codon
from eden.evo.context import Context
from eden.evo.operands import RegisterOperand, ConstOperand
from eden.evo.protein import Protein
from eden.evo.translate import Translator
from unittest import TestCase

class EvoTest(TestCase):
    def __init__(self, method_name):
        TestCase.__init__(self, method_name)
        self.context = Context()
        self.context.setregister(0, 1)
        
class AminoTest(EvoTest):
    def test(self):
        # 1 * 2 + 1 = 3
        amino1 = self.create_multi_amino()
        amino2 = self.create_add_amino()
        self.run_aminos((amino1, amino2), self.context)
        actual = self.context.getregister(0)
        self.assertEqual(3, actual)

    def create_multi_amino(self):
        left = RegisterOperand(0)
        right = ConstOperand(2)
        amino = MultiAmino(left, right)
        return amino

    def create_add_amino(self):
        left = RegisterOperand(0)
        right = ConstOperand(1)
        amino = AddAmino(left, right)
        return amino
    
    def run_aminos(self, aminos, context):
        for amino in aminos:
            amino.run(context)

class ProteinTest(EvoTest):
    def test(self):
        # 1 * 2 + 1 = 3
        amino1 = self.create_multi_amino()
        amino2 = self.create_add_amino()
        protein = Protein((amino1, amino2))
        protein.run(self.context)
        actual = self.context.getregister(0)
        self.assertEqual(3, actual)
        
    def create_multi_amino(self):
        left = RegisterOperand(0)
        right = ConstOperand(2)
        amino = MultiAmino(left, right)
        return amino

    def create_add_amino(self):
        left = RegisterOperand(0)
        right = ConstOperand(1)
        amino = AddAmino(left, right)
        return amino
    
class TranscodeTest(EvoTest):
    def test(self):
        # 1 * 2 + 1 = 3
        mapping = { 1 : AddAmino, 2 : MultiAmino }
        transcoder = Translator(mapping)
        chromosome = Chromosome((Codon(2, 128, 2), Codon(1, 128, 1)))
        protein = transcoder.translate(chromosome)
        protein.run(self.context)
        actual = self.context.getregister(0)
        self.assertEqual(3, actual)
        
class SexualCellTest(EvoTest):
    def test(self):
        # 1 * 2 + 1 = 3
        # or
        # (1 + 1) * 2 = 4
        mapping = { 1 : AddAmino, 2 : MultiAmino }
        left = Chromosome((Codon(2, 128, 2), Codon(1, 128, 1)))
        right = Chromosome((Codon(1, 128, 1), Codon(2, 128, 2)))
        cell = SexualCell(left, right, Translator(mapping))
        cell.run(self.context)
        actual = self.context.getregister(0)
        self.assertTrue(actual in (3, 4))